/**
 * GLB 3D模型文件处理库
 * 提供GLB文件解析、验证和基本操作功能
 */

export interface GLBHeader {
  magic: number;
  version: number;
  length: number;
}

export interface GLBChunk {
  type: number;
  data: Uint8Array;
}

export interface GLBFile {
  header: GLBHeader;
  jsonChunk?: GLBChunk;
  binaryChunk?: GLBChunk;
  jsonContent?: any;
}

export class GLBParser {
  /**
   * 解析二进制数据为GLB文件结构
   * @param data 二进制数据
   * @returns GLB文件结构
   * @throws 当数据无效时抛出错误
   */
  parse(data: Uint8Array): GLBFile {
    const view = new DataView(data.buffer);
    let offset = 0;

    // 解析头部
    const header: GLBHeader = {
      magic: view.getUint32(offset, true),
      version: view.getUint32(offset + 4, true),
      length: view.getUint32(offset + 8, true)
    };
    offset += 12;

    // 验证GLB标识
    if (header.magic !== 0x46546C67) { // 'glTF'的ASCII码反转
      throw new Error('无效的GLB文件: 错误的magic标识');
    }

    // 验证版本
    if (header.version !== 2) {
      throw new Error(`不支持的GLB版本: ${header.version}, 仅支持版本2`);
    }

    // 验证长度
    if (header.length !== data.length) {
      throw new Error(`GLB文件长度不匹配: 头部指定${header.length}字节, 实际${data.length}字节`);
    }

    const file: GLBFile = { header };
    const chunks: GLBChunk[] = [];

    // 解析块
    while (offset < data.length) {
      const chunkLength = view.getUint32(offset, true);
      const chunkType = view.getUint32(offset + 4, true); // 将 type 改为 chunkType
      offset += 8;

      const chunkData = data.subarray(offset, offset + chunkLength);
      chunks.push({ type: chunkType, data: chunkData }); // 使用 chunkType 替代 type

      offset += chunkLength;
    }

    // 分类块
    for (const chunk of chunks) {
      // JSON块 (0x4E4F534A)
      if (chunk.type === 0x4E4F534A) {
        if (file.jsonChunk) {
          throw new Error('GLB文件中包含多个JSON块');
        }
        file.jsonChunk = chunk;

        // 解析JSON内容
        const textDecoder = new TextDecoder('utf-8');
        const jsonText = textDecoder.decode(chunk.data);
        file.jsonContent = JSON.parse(jsonText);
      }
      // 二进制块 (0x004E4942)
      else if (chunk.type === 0x004E4942) {
        if (file.binaryChunk) {
          throw new Error('GLB文件中包含多个二进制块');
        }
        file.binaryChunk = chunk;
      }
      // 未知块类型
      else {
        console.warn(`发现未知的GLB块类型: 0x${chunk.type.toString(16).toUpperCase()}`);
      }
    }

    // 验证必要的块
    if (!file.jsonChunk) {
      throw new Error('GLB文件缺少JSON块');
    }

    return file;
  }

  /**
   * 验证GLB文件结构是否有效
   * @param file 已解析的GLB文件
   * @returns 验证结果
   */
  validate(file: GLBFile): boolean {
    try {
      // 检查JSON内容的基本结构
      if (!file.jsonContent) {
        return false;
      }

      // 检查是否包含场景或模型
      if (!file.jsonContent.scenes || file.jsonContent.scenes.length === 0) {
        console.warn('GLB验证警告: 没有包含场景');
      }

      // 检查二进制块引用（如果有）
      if (file.binaryChunk && file.jsonContent.buffers && file.jsonContent.buffers.length > 0) {
        const buffer = file.jsonContent.buffers[0];
        if (buffer.byteLength !== file.binaryChunk.data.length) {
          console.warn(`GLB验证警告: 二进制块长度不匹配，JSON中指定${buffer.byteLength}字节，实际${file.binaryChunk.data.length}字节`);
        }
      }

      return true;
    } catch (error) {
      console.error('GLB验证失败:', error);
      return false;
    }
  }

  /**
   * 将GLB文件结构转换回二进制数据
   * @param file GLB文件结构
   * @returns 二进制数据
   */
  serialize(file: GLBFile): Uint8Array {
    if (!file.jsonChunk) {
      throw new Error('无法序列化GLB文件: 缺少JSON块');
    }

    // 计算总长度
    let totalLength = 12; // 头部长度

    // 计算所有块的总长度
    totalLength += 8 + file.jsonChunk.data.length; // JSON块头部 + 数据
    if (file.binaryChunk) {
      totalLength += 8 + file.binaryChunk.data.length; // 二进制块头部 + 数据
    }

    // 创建缓冲区
    const buffer = new ArrayBuffer(totalLength);
    const view = new DataView(buffer);
    let offset = 0;

    // 写入头部
    view.setUint32(offset, 0x46546C67, true); // magic
    offset += 4;
    view.setUint32(offset, 2, true); // version
    offset += 4;
    view.setUint32(offset, totalLength, true); // length
    offset += 4;

    // 写入JSON块
    view.setUint32(offset, file.jsonChunk.data.length, true); // 块长度
    offset += 4;
    view.setUint32(offset, 0x4E4F534A, true); // 块类型 (JSON)
    offset += 4;
    new Uint8Array(buffer).set(file.jsonChunk.data, offset);
    offset += file.jsonChunk.data.length;

    // 写入二进制块（如果有）
    if (file.binaryChunk) {
      view.setUint32(offset, file.binaryChunk.data.length, true); // 块长度
      offset += 4;
      view.setUint32(offset, 0x004E4942, true); // 块类型 (BIN)
      offset += 4;
      new Uint8Array(buffer).set(file.binaryChunk.data, offset);
      offset += file.binaryChunk.data.length;
    }

    return new Uint8Array(buffer);
  }
}

// 导出便捷函数
export function parseGLB(data: Uint8Array): GLBFile {
  const parser = new GLBParser();
  return parser.parse(data);
}

export function validateGLB(file: GLBFile): boolean {
  const parser = new GLBParser();
  return parser.validate(file);
}

export function serializeGLB(file: GLBFile): Uint8Array {
  const parser = new GLBParser();
  return parser.serialize(file);
}

// 导出库版本信息
export const version = '1.0.0';